package com.lnj.messages.servise;

import com.lnj.messages.mapper.OrdersMapper;
import com.lnj.messages.mapper.ProductMapper;
import com.lnj.messages.utiles.ProductUserBehavior;
import com.lnj.messages.utiles.UserBehaviorUtil;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
import org.apache.mahout.cf.taste.impl.model.GenericPreference;
import org.apache.mahout.cf.taste.impl.model.GenericUserPreferenceArray;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.model.Preference;
import org.apache.mahout.cf.taste.model.PreferenceArray;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 混合推荐服务 - 结合用户浏览记录和购买记录进行商品推荐
 *
 * <p>实现基于协同过滤的推荐算法，结合用户行为数据和商品热度数据</p>
 *
 * <p>主要功能：</p>
 * <ul>
 *   <li>基于用户浏览历史的相似商品推荐</li>
 *   <li>基于用户购买历史的相似商品推荐</li>
 *   <li>热门商品推荐</li>
 *   <li>多策略混合推荐结果</li>
 * </ul>
 */
@Service
public class HybridRecommenderService {

    @Autowired
    private UserBehaviorUtil userBehaviorUtil; // 用户行为工具类
    @Autowired
    private ProductMapper productMapper; // 商品Mapper

    /**
     * 基于用户行为的混合推荐
     * @param userId 用户ID
     * @param howMany 需要推荐的商品数量
     * @return 推荐商品ID列表，按推荐分数从高到低排序
     */
    public List<Long> recommendItems(Long userId, int howMany) {
        //获取所有的商品ID
        List<Long> productIds = productMapper.selectAllProductId();

        // 1.获取所有的用户行为数据 （最近浏览和购买记录）
        List<ProductUserBehavior> productUserBehaviors = userBehaviorUtil.getAllUserBehaviors(productIds);

        // 2. 构建Mahout数据模型
        DataModel model = buildDataModel(productUserBehaviors);

        try {
            // 1. 创建用户相似度计算器
            // PearsonCorrelationSimilarity使用皮尔逊相关系数计算用户间相似度
            UserSimilarity similarity = new PearsonCorrelationSimilarity(model);

            // 2. 定义用户邻域（寻找相似用户）
            // NearestNUserNeighborhood会找出与目标用户最相似的N个用户
            UserNeighborhood neighborhood = new NearestNUserNeighborhood(20, similarity, model);

            // 3. 创建基于用户的推荐器
            // GenericUserBasedRecommender是实现协同过滤的核心类
            Recommender recommender = new GenericUserBasedRecommender(model, neighborhood, similarity);

            // 4. 生成推荐结果
            // recommend()方法为指定用户生成商品推荐
            // 返回的RecommendedItem包含商品ID和预测评分值
            List<RecommendedItem> recommendations = recommender.recommend(userId, howMany);

            // 5. 转换推荐结果为需要的格式
            // 这里将RecommendedItem流式处理，提取商品ID并转换为Long类型
            return recommendations.stream()
                    .map(RecommendedItem::getItemID)  // 获取商品ID(long类型)
                    .map(Long::valueOf)              // 转换为Long对象
                    .collect(Collectors.toList());    // 收集为List<Long>
        } catch (TasteException e) {
            throw new RuntimeException("推荐失败", e);
        }

    }


    private DataModel buildDataModel(List<ProductUserBehavior> behaviors) {
        // 使用 FastByIDMap 来存储用户偏好数据
        FastByIDMap<PreferenceArray> userData = new FastByIDMap<>();

        // 按用户ID分组行为数据
        Map<Long, List<ProductUserBehavior>> behaviorsByUser = behaviors.stream()
                .collect(Collectors.groupingBy(ProductUserBehavior::getUserId));

        // 为每个用户构建偏好数组
        behaviorsByUser.forEach((userId, userBehaviors) -> {
            List<Preference> prefs = new ArrayList<>();

            for (ProductUserBehavior behavior : userBehaviors) {
                float preferenceValue = calculatePreferenceValue(behavior);
                if (preferenceValue > 0) {
                    prefs.add(new GenericPreference(
                            userId,
                            behavior.getProductId(),
                            preferenceValue
                    ));
                }
            }

            if (!prefs.isEmpty()) {
                userData.put(userId, new GenericUserPreferenceArray(prefs));
            }
        });

        return new GenericDataModel(userData);
    }


    // 添加计算偏好值的方法
    private float calculatePreferenceValue(ProductUserBehavior behavior) {
        float preferenceValue = 0f;

        // 根据不同的行为类型设置偏好值
        if (Boolean.TRUE.equals(behavior.getView())) {
            preferenceValue += 1.0f; // 浏览行为
        }

        if (Boolean.TRUE.equals(behavior.getPurchase())) {
            preferenceValue += 3.0f; // 购买行为权重更高
        }

        if (Boolean.TRUE.equals(behavior.getFavorite())) {
            preferenceValue += 2.0f; // 收藏行为
        }

        return preferenceValue;
    }


}